package org.hackystat.devcathlon.event.impl;

import static org.junit.Assert.assertEquals;
import javax.xml.datatype.XMLGregorianCalendar;
import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.event.Event;
import org.hackystat.devcathlon.event.EventScore;
import org.hackystat.devcathlon.match.Match;
import org.hackystat.devcathlon.team.Team;
import org.hackystat.devcathlon.test.DevcathlonTestHelper;
import org.hackystat.devcathlon.user.User;
import org.hackystat.devcathlon.user.UserManager;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.BeforeClass;
import org.junit.Test;


/**
 * Tests the No MIAs event.
 * 
 * @author Daniel Arakaki
 */
public class TestNoMias extends DevcathlonTestHelper {
  
  /**Point loss for one non-working member.*/
  private static int oneNoDevTime = -10;
  
  /**Point loss for the entire team not working.*/
  private static int allNoDevTime = -20;
  
  /**A 72 hour time period.*/
  private static int timePeriod = 3;
  
  /**Test team name.*/
  private String teamName = "TestTeam";
  
  /**Test team owner.*/
  private String teamOwner = "TheOwner";
  
  /**Test match.*/
  private String matchName = "TestMatch";
  
  /**Test team member 1.*/
  private String member1 = "Member1";
  
  /**Test team member 2.*/
  private String member2 = "Member2";
  
  /**UserMananger instance to access team members.*/
  private UserManager manager;
  
  /**
   * Sets up the configuration...
   * 
   * @throws Exception If there is an error with the configuration.
   */
 
  @BeforeClass
  public static void setupConfiguration() throws Exception {
    String eventName = NoMias.eventName;
    ConfigurationManager configManager = ConfigurationManager.getInstance();
    configManager.setBaseScoreWeight(eventName, 1);
    configManager.getConfiguration(eventName);
    configManager.setWakeupInterval(eventName, 1440);
    configManager.addProperty(eventName, NoMias.oneNoDevTime, String.valueOf(oneNoDevTime));
    configManager.addProperty(eventName, NoMias.allNoDevTimeKey, String.valueOf(allNoDevTime));
    configManager.addProperty(eventName, NoMias.timePeriodKey, String.valueOf(timePeriod));
  }
  
  /**
   * Testing for all members who developed.
   * 
   * @throws Exception If error with making team.
   */
  @Test
  public void testAllDevTime() throws Exception {
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    Event event = new NoMias();
    
    Project project = getProject(teamOwner, teamName);
    Match match = addSimpleMatch(matchName, team, project, event);
    
    //need a time object set it outside of "now".
    XMLGregorianCalendar currentTime = Tstamp.makeTimestamp();
    
    this.makeDevTimeData(team.getOwner(), project, Tstamp.incrementDays(currentTime, -3), 10);
    this.makeDevTimeData(team.getOwner(), project, Tstamp.incrementDays(currentTime, -2), 10);
    this.makeDevTimeData(team.getOwner(), project, Tstamp.incrementDays(currentTime, -1), 10);
    
    //set dev for all members over three days
    for (User users : team.getMembers()) {
      this.makeDevTimeData(users, project, Tstamp.incrementDays(currentTime, -3), 15);
      this.makeDevTimeData(users, project, Tstamp.incrementDays(currentTime, -2), 10);
      this.makeDevTimeData(users, project, Tstamp.incrementDays(currentTime, -1), 5);
    }
   
    EventScore score = event.computeScore(match, team, currentTime);
    assertEquals("check for score1", 0, score.getBaseScore());
    assertEquals("Check for bonus1", 0, score.getBonusScore(NoMias.allNoDevTimeKey));
    assertEquals("check for points1", 0, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Tests for a developer with no dev time.
   * 
   * @throws Exception If error with making team.
   */
  @Test
  public void testOneNoDevTime() throws Exception {
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    Event event = new NoMias();
    
    Project project = getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
   
    //need a time object set it outside of "now".
    XMLGregorianCalendar currentTime = Tstamp.makeTimestamp();
    
    int teamSize = team.getMembers().size();
    manager = UserManager.getInstance();
    
    //set up members
    Object objArray[] = team.getMembers().toArray();
    User userArray[] = new User[teamSize];
    User member[] = new User[teamSize];
    
    for (int i = 0; i < teamSize; i++) {
      userArray[i] = (User)objArray[i];
      member[i] = manager.getUser(userArray[i].getEmail());
    }
    
    //set no dev time for member1 over three days
    for (int i = 0, j = timePeriod; i < timePeriod; i++, j--) {
      this.makeDevTimeData(member[0], project, Tstamp.incrementDays(currentTime, -j), 0);
    }
    
    //set dev time for member2 and owner over timePeriod days
    for (int k = 0, j = timePeriod; k < timePeriod; k++, j--) {
      this.makeDevTimeData(team.getOwner(), project, Tstamp.incrementDays(currentTime, -j), 10);
      this.makeDevTimeData(member[1], project, Tstamp.incrementDays(currentTime, -j), k * 5);
    }
   
    EventScore score = event.computeScore(match, team, currentTime);
    assertEquals("check for score2", -10, score.getBaseScore());
    assertEquals("Check for bonus2", 0, score.getBonusScore(NoMias.allNoDevTimeKey));
    assertEquals("check for points2", -10, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Tests for second developer with no dev time.
   * 
   * @throws Exception If error with making team.
   */
  @Test
  public void testOneNoDevTimeTwo() throws Exception {
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    Event event = new NoMias();
    
    Project project = getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
   
    //need a time object set it outside of "now".
    XMLGregorianCalendar currentTime = Tstamp.makeTimestamp();
    
    int teamSize = team.getMembers().size();
    manager = UserManager.getInstance();
    
    //set up members
    Object objArray[] = team.getMembers().toArray();
    User userArray[] = new User[teamSize];
    User member[] = new User[teamSize];
    
    for (int i = 0; i < teamSize; i++) {
      userArray[i] = (User)objArray[i];
      member[i] = manager.getUser(userArray[i].getEmail());
    }
    
    //set dev time for member1 and owner over timePeriod days
    for (int i = 0, j = timePeriod; i < timePeriod; i++, j--) {
      this.makeDevTimeData(team.getOwner(), project, Tstamp.incrementDays(currentTime, -j), 10);
      this.makeDevTimeData(member[0], project, Tstamp.incrementDays(currentTime, -j), i * 5);
    }
    
    //set no dev time for member2 over timePeriod days.
    for (int k = 0, j = timePeriod; k < timePeriod; k++, j--) {
      this.makeDevTimeData(member[1], project, Tstamp.incrementDays(currentTime, -j), 0);
    }
   
    EventScore score = event.computeScore(match, team, currentTime);
    assertEquals("check for score3", -10, score.getBaseScore());
    assertEquals("Check for bonus3", 0, score.getBonusScore(NoMias.allNoDevTimeKey));
    assertEquals("check for points3", -10, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
  
  /**
   * Tests for all developers with no dev time.
   * 
   * @throws Exception If error with making team.
   */
  @Test
  public void testAllNoDevTime() throws Exception {
    Team team = makeTeam(teamName, teamOwner, member1, member2);
    
    Event event = new NoMias();
    
    Project project = getProject(teamOwner, teamName);
    Match match = this.addSimpleMatch(matchName, team, project, event);
   
    //need a time object set it outside of "now".
    XMLGregorianCalendar currentTime = Tstamp.makeTimestamp();
    
    int teamSize = team.getMembers().size();
    manager = UserManager.getInstance();
    
    //set up members
    Object objArray[] = team.getMembers().toArray();
    User userArray[] = new User[teamSize];
    User member[] = new User[teamSize];
    
    for (int i = 0; i < teamSize; i++) {
      userArray[i] = (User)objArray[i];
      member[i] = manager.getUser(userArray[i].getEmail());
    }
    
    //all members no dev time
    for (int i = 0, j = timePeriod; i < timePeriod; i++, j--) {
      this.makeDevTimeData(team.getOwner(), project, Tstamp.incrementDays(currentTime, -j), 0);
      for (int n = 0; n < teamSize; n++) {
        this.makeDevTimeData(member[n], project, Tstamp.incrementDays(currentTime, -j), 0);
      }
    }
   
    EventScore score = event.computeScore(match, team, currentTime);
    assertEquals("check for score4", 0, score.getBaseScore());
    assertEquals("Check for bonus4", -20, score.getBonusScore(NoMias.allNoDevTimeKey));
    assertEquals("check for points4", 400, event.computePoints(score));
    this.deleteTeam(teamName);
    this.deleteMatch(matchName);
  }
}
